/*
 * Copyright (c) 2022 HiSilicon (Shanghai) Technologies CO., LIMITED.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <opencv2/face/facerec.hpp> 
#include <dirent.h>
#include <opencv2/objdetect/objdetect.hpp>  
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include "tennis_detect.h"
#include "hisignalling.h"
#include "sample_comm_nnie.h"
#include "sample_comm_ive.h"
#include "sample_media_ai.h"
#include "vgs_img.h"
#include "misc_util.h"

using namespace std;
using namespace cv;
using namespace cv::face;

CascadeClassifier faceDetect;
int uartCx = 0;

Ptr<FaceRecognizer> LBPHRecog = LBPHFaceRecognizer::create(1, 8 ,8, 8,30);
//函数声明  
vector<Rect> FaceDetector(Mat img);//检测人脸，并返回人脸区域  
void GetFilesNameAndLabels(char *path, vector<string>& filesName,vector<string>& labelsInfo);



static IVE_SRC_IMAGE_S pstSrc;
static IVE_DST_IMAGE_S pstDst;
static IVE_CSC_CTRL_S stCscCtrl;

static HI_VOID IveImageParamCfg(IVE_SRC_IMAGE_S *pstSrc, IVE_DST_IMAGE_S *pstDst,
    VIDEO_FRAME_INFO_S *srcFrame)
{
    pstSrc->enType = IVE_IMAGE_TYPE_YUV420SP;
    pstSrc->au64VirAddr[0] = srcFrame->stVFrame.u64VirAddr[0];
    pstSrc->au64VirAddr[1] = srcFrame->stVFrame.u64VirAddr[1];
    pstSrc->au64VirAddr[2] = srcFrame->stVFrame.u64VirAddr[2]; // 2: Image data virtual address

    pstSrc->au64PhyAddr[0] = srcFrame->stVFrame.u64PhyAddr[0];
    pstSrc->au64PhyAddr[1] = srcFrame->stVFrame.u64PhyAddr[1];
    pstSrc->au64PhyAddr[2] = srcFrame->stVFrame.u64PhyAddr[2]; // 2: Image data physical address

    pstSrc->au32Stride[0] = srcFrame->stVFrame.u32Stride[0];
    pstSrc->au32Stride[1] = srcFrame->stVFrame.u32Stride[1];
    pstSrc->au32Stride[2] = srcFrame->stVFrame.u32Stride[2]; // 2: Image data span

    pstSrc->u32Width = srcFrame->stVFrame.u32Width;
    pstSrc->u32Height = srcFrame->stVFrame.u32Height;

    pstDst->enType = IVE_IMAGE_TYPE_U8C3_PACKAGE;
    pstDst->u32Width = pstSrc->u32Width;
    pstDst->u32Height = pstSrc->u32Height;
    pstDst->au32Stride[0] = pstSrc->au32Stride[0];
    pstDst->au32Stride[1] = 0;
    pstDst->au32Stride[2] = 0; // 2: Image data span
}

static HI_S32 yuvFrame2rgb(VIDEO_FRAME_INFO_S *srcFrame, IPC_IMAGE *dstImage)
{
    IVE_HANDLE hIveHandle;
    HI_S32 s32Ret = 0;
    stCscCtrl.enMode = IVE_CSC_MODE_PIC_BT709_YUV2RGB; // IVE_CSC_MODE_VIDEO_BT601_YUV2RGB
    IveImageParamCfg(&pstSrc, &pstDst, srcFrame);

    s32Ret = HI_MPI_SYS_MmzAlloc_Cached(&pstDst.au64PhyAddr[0], (void **)&pstDst.au64VirAddr[0],
        "User", HI_NULL, pstDst.u32Height*pstDst.au32Stride[0] * 3); // 3: multiple
    if (HI_SUCCESS != s32Ret) {
        HI_MPI_SYS_MmzFree(pstDst.au64PhyAddr[0], (void *)pstDst.au64VirAddr[0]);
        SAMPLE_PRT("HI_MPI_SYS_MmzFree err\n");
        return s32Ret;
    }

    s32Ret = HI_MPI_SYS_MmzFlushCache(pstDst.au64PhyAddr[0], (void *)pstDst.au64VirAddr[0],
        pstDst.u32Height*pstDst.au32Stride[0] * 3); // 3: multiple
    if (HI_SUCCESS != s32Ret) {
        HI_MPI_SYS_MmzFree(pstDst.au64PhyAddr[0], (void *)pstDst.au64VirAddr[0]);
        return s32Ret;
    }
    // 3: multiple
    memset_s((void *)pstDst.au64VirAddr[0], pstDst.u32Height*pstDst.au32Stride[0] * 3,
        0, pstDst.u32Height*pstDst.au32Stride[0] * 3); // 3: multiple
    HI_BOOL bInstant = HI_TRUE;

    s32Ret = HI_MPI_IVE_CSC(&hIveHandle, &pstSrc, &pstDst, &stCscCtrl, bInstant);
    if (HI_SUCCESS != s32Ret) {
        HI_MPI_SYS_MmzFree(pstDst.au64PhyAddr[0], (void *)pstDst.au64VirAddr[0]);
        return s32Ret;
    }

    if (HI_TRUE == bInstant) {
        HI_BOOL bFinish = HI_TRUE;
        HI_BOOL bBlock = HI_TRUE;
        s32Ret = HI_MPI_IVE_Query(hIveHandle, &bFinish, bBlock);
        while (HI_ERR_IVE_QUERY_TIMEOUT == s32Ret) {
            usleep(100); // 100: usleep time
            s32Ret = HI_MPI_IVE_Query(hIveHandle, &bFinish, bBlock);
        }
    }
    dstImage->u64PhyAddr = pstDst.au64PhyAddr[0];
    dstImage->u64VirAddr = pstDst.au64VirAddr[0];
    dstImage->u32Width = pstDst.u32Width;
    dstImage->u32Height = pstDst.u32Height;

    return HI_SUCCESS;
}

static HI_S32 frame2Mat(VIDEO_FRAME_INFO_S *srcFrame, Mat &dstMat)
{
    HI_U32 w = srcFrame->stVFrame.u32Width;
    HI_U32 h = srcFrame->stVFrame.u32Height;
    int bufLen = w * h * 3;
    HI_U8 *srcRGB = NULL;
    IPC_IMAGE dstImage;
    if (yuvFrame2rgb(srcFrame, &dstImage) != HI_SUCCESS) {
        SAMPLE_PRT("yuvFrame2rgb err\n");
        return HI_FAILURE;
    }
    srcRGB = (HI_U8 *)dstImage.u64VirAddr;
    dstMat.create(h, w, CV_8UC3);
    memcpy_s(dstMat.data, bufLen * sizeof(HI_U8), srcRGB, bufLen * sizeof(HI_U8));
    HI_MPI_SYS_MmzFree(dstImage.u64PhyAddr, (void *)&(dstImage.u64VirAddr));
    return HI_SUCCESS;
}

HI_S32 tennis_detect::TennisDetectLoad(uintptr_t* model)
{
    /* uart open init */
    uartCx = UartOpenInit();
    if (uartCx < 0) {
        printf("uart1 open failed\r\n");
    } else {
        printf("uart1 open successed\r\n");
    }
    Mat src;
    vector<Mat> trainPic;//训练图片  
    vector<int> labels;//与训练图片一一对应的标签  
    HI_S32 ret = 1;
    *model = 1;
    SAMPLE_PRT("TennisDetectLoad success\n");
    string picture1 = "/userdata/smalljpgset/0.jpg";
    string picture2 = "/userdata/smalljpgset/1.jpg";
    string picture3 = "/userdata/smalljpgset/2.jpg"; 
    string picture4 = "/userdata/smalljpgset/3.jpg";
    SAMPLE_PRT("LBPHRecog create success\n");
    src = imread(picture1); 
    cvtColor(src, src, COLOR_RGB2GRAY);   
    trainPic.push_back(src);  
    labels.push_back(0); 
    src = imread(picture2);        
    cvtColor(src, src, COLOR_RGB2GRAY);  
    trainPic.push_back(src);  
    labels.push_back(1);
    src = imread(picture3);         
    cvtColor(src, src, COLOR_RGB2GRAY);  
    trainPic.push_back(src);  
    labels.push_back(2);
    src = imread(picture4);        
    cvtColor(src, src, COLOR_RGB2GRAY);  
    trainPic.push_back(src);  
    labels.push_back(3);
    LBPHRecog->train(trainPic, labels);
    SAMPLE_PRT("LBPHRecog->train success\n");
    return ret;
}

HI_S32 tennis_detect::TennisDetectUnload(uintptr_t model)
{
    model = 0;

    return HI_SUCCESS;
}

vector<Rect> FaceDetector(Mat img)  
{  
    Mat src = Mat::zeros(240, 320, img.type());  
    vector<Rect> faces;  
    cvtColor(img, img, COLOR_RGB2GRAY);  
    resize(img, src, src.size());  
    faceDetect.detectMultiScale(img, faces, 1.2, 6, 0);  
    return faces;  
}  
  


HI_S32 tennis_detect::TennisDetectCal(uintptr_t model, VIDEO_FRAME_INFO_S *srcFrm, VIDEO_FRAME_INFO_S *dstFrm)
{
    (void)model;
    int ret = 0;
    RectBox boxs[32] = {0}; // 32: TENNIS_OBJ_MAX
    int j = 0;
    Mat frame;
    frame2Mat(srcFrm, frame);
    if (frame.size == 0) {
        SAMPLE_PRT("frame is null\n");
        return HI_FAILURE;
    }
    
    Mat facePic;
    Mat recogPic;

    vector<Rect> faces;  
    
    int result;  

    faceDetect.load("/userdata/models/haarcascade_frontalface_alt2.xml");
    SAMPLE_PRT("faceDetectLoad success\n");
    recogPic = Mat::zeros(200, 200, frame.type());
    Mat recogPic1=frame.clone();
    cvtColor(recogPic1, recogPic1, COLOR_RGB2GRAY);
    result = LBPHRecog->predict(recogPic1);
    SAMPLE_PRT("result1: %d\n",result);
    SAMPLE_PRT("LBPHRecog->predict recogPic1 success\n"); 
    faces = FaceDetector(frame);
    SAMPLE_PRT("FaceDetector success\n");
    if(faces.size()==0){
        SAMPLE_PRT("FaceDetector fail\n");
    }
    if(result!=-1){
        switch(result){
            case 0: ;break;
            case 1: ;break;
            case 2:
            UartSendRead(uartCx, ForefingerGesture); break;
            case 3: ;break;
            default:;break;
        }
    }
    for(size_t i = 0; i<faces.size(); i++){
        /*facePic = frame(Rect(faces[i]));
        SAMPLE_PRT("LBPHRecog->predict recogPic success\n");  
        resize(facePic, recogPic, recogPic.size());   
        cvtColor(recogPic, recogPic, COLOR_RGB2GRAY);   
        result = LBPHRecog->predict(recogPic);
        SAMPLE_PRT("result: %d\n",result);*/
        boxs[j].xmin = faces[j].x*3; // 3: optimized value
        boxs[j].ymin = faces[j].y*2.25; // 2.25: optimized value
        boxs[j].xmax = boxs[j].xmin + faces[j].width*3; // 3: optimized value
        boxs[j].ymax = boxs[j].ymin + faces[j].height*2.25; // 2.25: optimized value
        j++;
    }

     // 25: detect boxesNum
    if (j > 0 && j <= 25) {
        SAMPLE_PRT("box num:%d\n", j);
        MppFrmDrawRects(dstFrm, boxs, j, RGB888_RED, 2); // 2: DRAW_RETC_THICK
    }

    return ret;
}